package com.tbit.main.service.impl;

import com.tbit.main.constant.MachineTagConstant;
import com.tbit.main.constant.TagStatus;
import com.tbit.main.dao.core.MachineDao;
import com.tbit.main.dao.core.MachineTagDao;
import com.tbit.main.dao.core.TagDao;
import com.tbit.main.pojo.AccountUser;
import com.tbit.main.pojo.Machine;
import com.tbit.main.pojo.MachineTag;
import com.tbit.main.pojo.TagBaseInfo;
import com.tbit.main.pojo.entity.TagAndMachineBind;
import com.tbit.main.service.MachineTagService;
import com.tbit.main.util.Assert;
import com.tbit.main.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (MachineTag)表服务实现类
 *
 * @author shanyong.mo
 * @since 2024-11-22 10:33:42
 */
@Slf4j
@Service("machineTagService")
public class MachineTagServiceImpl implements MachineTagService {
    @Resource
    private MachineTagDao machineTagDao;
    @Resource
    private MachineDao machineDao;
    @Autowired
    private TagDao tagDao;

    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public MachineTag queryById(Integer id) {
        return this.machineTagDao.queryById(id);
    }

    /**
     * @description: 批量查询
     * @param: idList 查询的id集合
     * @return: java.util.List<MachineTag>
     */
    @Override
    public List<MachineTag> queryByIds(List<Integer> idList) {
        return this.machineTagDao.queryByIds(idList);
    }


    /**
     * 分页查询
     *
     * @param machineTag 筛选条件
     * @param pageNum    页码
     * @param pageSize   每页数据量
     * @return 查询结果
     */
    @Override
    public List<MachineTag> queryByPage(MachineTag machineTag, Integer pageNum,
                                        Integer pageSize, String search) {
        return this.machineTagDao.queryAllByLimit(machineTag,
                Objects.nonNull(pageNum) && Objects.nonNull(pageSize) ? (pageNum - 1) * pageSize : null, pageSize, search);
    }


    /**
     * 查询总数
     *
     * @param machineTag 筛选条件
     * @param search     搜索内容
     * @return 查询结果
     */
    @Override
    public Integer queryCount(MachineTag machineTag, String search) {
        return this.machineTagDao.count(machineTag, search);
    }

    /**
     * 新增数据
     *
     * @param machineTag 实例对象
     * @return 实例对象
     */
    @Override
    public MachineTag insert(MachineTag machineTag) {
        this.machineTagDao.insert(machineTag);
        return machineTag;
    }

    /**
     * 修改数据
     *
     * @param machineTag 实例对象
     * @return 实例对象
     */
    @Override
    public MachineTag update(MachineTag machineTag) {
        this.machineTagDao.update(machineTag);
        return this.queryById(machineTag.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.machineTagDao.deleteById(id) > 0;
    }

    /**
     * 新增数据（会判断null字段，null字段不插入）
     *
     * @param machineTag 实例对象
     * @return 实例对象
     */
    @Override
    public MachineTag insertCheckNull(MachineTag machineTag) {
        this.machineTagDao.insertCheckNull(machineTag);
        return machineTag;
    }

    /**
     * 更新数据（会判断null字段，null字段不更新）
     *
     * @param machineTag 实例对象
     * @return 实例对象
     */
    @Override
    public MachineTag updateCheckNull(MachineTag machineTag) {
        this.machineTagDao.updateCheckNull(machineTag);
        return this.queryById(machineTag.getId());
    }
    /**
     * @description: 批量绑定车辆的标签
     * @author: mo.shanyong
     * @date: 2024/11/25 13:26
     * @param: userCodeList 车辆编号
     * @param: tagIdList 绑定的标签id
     */
    @Override
    public void bindTagBatch(List<Integer> machineIdList, List<Integer> tagIdList, AccountUser accountUser) {
        List<MachineTag> machineTagList = machineTagDao.getMachineTagByMachineId(machineIdList);

        Map<Integer, List<MachineTag>> machineTagMap = CollectionUtils.isEmpty(machineTagList) ?
                new HashMap<>() : machineTagList.stream().collect(Collectors.groupingBy(MachineTag::getMachineId));

        //绑定车辆标签
        this.addMachineTag(machineIdList,machineTagMap,tagIdList,accountUser);

    }
    /**
     * @description: 取消绑定车辆标签
     * @author: mo.shanyong
     * @date: 2024/11/25 16:19
     * @param: machineIdList 车辆Id
     * @param: tagIdList 标签id
     * @param: accountUser 当前登录用户
     */
    @Override
    public void cancelTagBatch(List<Integer> machineIdList, List<Integer> tagIdList, AccountUser accountUser) {
        Map<String, Object> params = new HashMap<>();
        params.put("machineIds", StringUtil.getListString(machineIdList));
        List<Machine> machineList = machineDao.getByMachineIdsAll(params);
        if (CollectionUtils.isEmpty(machineList)){
            return;
        }
        this.updateMachineNotBindTag(machineIdList,tagIdList,accountUser);
    }

    /**
     * @description: 车辆详情页管理车辆标签
     * @author: mo.shanyong
     * @date: 2024/12/16 9:07
     * @param: machineId 车辆id
     * @param: tagIdList 标签id
     */
    @Transactional(rollbackFor = Exception.class,value = "coreTransactionManager")
    @Override
    public void manageTag(Integer machineId, List<Integer> tagIdList,AccountUser accountUser) {
        //如果标签id为空，则取消车辆的全部标签,排除禁用的
        MachineTag query = new MachineTag();
        query.setMachineId(machineId);
        query.setBindStatus(1);
        List<MachineTag> machineTagList = machineTagDao.queryAllByLimit(query,null,null,null);
        List<Integer> machineTagIdList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(machineTagList)){
            machineTagIdList.addAll(machineTagList.stream().map(machineTag -> {
                return Integer.valueOf(String.valueOf(machineTag.getTagId()));
            }).collect(Collectors.toList()));
        }
        //获取车辆上绑定的禁用的标签
        List<Integer> bindDisableTagIds = machineTagDao.getBindDisableTagIds(machineId);
        if (CollectionUtils.isEmpty(tagIdList)){
            //过滤掉现在车辆上绑定了的禁用的标签
            machineTagIdList = machineTagIdList.stream().filter(tagId ->{
                return !bindDisableTagIds.contains(tagId);
            }).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(machineTagIdList)){
                return;
            }
            this.updateMachineNotBindTag(Arrays.asList(machineId),machineTagIdList,accountUser);
            return;
        }
        Machine machine = machineDao.getByMachineId(machineId);
        if (Objects.isNull(machine)){
            log.info("找不到车辆--->{}",machineId);
            return;
        }
        //找到车辆未绑定的标签进行绑定
        this.findNotBindTagToBing(machine,machineTagIdList,tagIdList,accountUser);
        //找到要取消绑定的车辆
        this.findBindToNotBind(machine,machineTagIdList,tagIdList,bindDisableTagIds,accountUser);

    }

    /**
     * @description: 取消绑定车辆编号
     * @author: mo.shanyong
     * @date: 2024/11/25 14:39
     * @param: machineIdList车辆d
     * @param: tagIdList 标签id(不传就取消设备所有绑定的标签)
     * @param: accountUser
     */
    private void updateMachineNotBindTag(List<Integer> machineIdList,List<Integer> tagIdList, AccountUser accountUser){
        machineTagDao.cancelTagByMachineIds(machineIdList,tagIdList,MachineTagConstant.CANCEL_TYPE_HAND, accountUser.getAccountUserId(),
                accountUser.getPhone(), MachineTagConstant.USER_TYPE_MAINTAIN);
    }

    /**
     * @description: 添加要绑定的车辆标签
     * @author: mo.shanyong
     * @date: 2024/11/25 15:23
     * @param: machineIdList 车辆id
     * @param: machineTagMap 已绑定的车辆标签map
     * @param: tagIdList 要绑定的车辆标签id
     * @param: accountUser 当前登录人
     */
    private void addMachineTag(List<Integer> machineIdList,Map<Integer,List<MachineTag>> machineTagMap,
                               List<Integer> tagIdList,AccountUser accountUser){
        Map<String, Object> params = new HashMap<>();
        params.put("machineIds", StringUtil.getListString(machineIdList));
        List<Machine> machineList = machineDao.getByMachineIdsAll(params);
        if (CollectionUtils.isEmpty(machineList)){
            return;
        }
        for (Machine machine : machineList) {
            List<MachineTag> machineTags = machineTagMap.get(machine.getMachineId());
            List<Integer> machineTagIdList = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(machineTags)){
                machineTagIdList.addAll(machineTags.stream().map(machineTag -> {
                    return Integer.valueOf(String.valueOf(machineTag.getTagId()));
                }).collect(Collectors.toList()));
            }
            this.findNotBindTagToBing(machine,machineTagIdList,tagIdList,accountUser);
        }
    }

    /**
     * @description: 生成车辆绑定信息
     * @author: mo.shanyong
     * @date: 2024/11/25 15:18
     * @param: noBindTagIdList 车辆Id
     * @param: accountUser 登录人
     * @return: java.util.List<com.tbit.main.pojo.MachineTag>
     */
    public List<MachineTag> getMachineTagByMId(List<Integer> noBindTagIdList,AccountUser accountUser,Machine machine){
        List<MachineTag> machineTagList = new ArrayList<>();
        Date now = new Date();
        for (Integer tagId : noBindTagIdList) {
            MachineTag machineTag = new MachineTag();
            machineTag.setMachineId(machine.getMachineId());
            machineTag.setBindStatus(MachineTagConstant.BIND_TAG_STATUS);
            machineTag.setAccountId(machine.getAccountId());
            machineTag.setBrandId(accountUser.getBrandId());
            machineTag.setTagTime(now);
            machineTag.setCreateTime(now);
            machineTag.setOperatorId(accountUser.getAccountUserId());
            machineTag.setOperatorPhone(accountUser.getPhone());
            machineTag.setUpdateTime(now);
            machineTag.setUserCode(machine.getUserCode());
            machineTag.setUserType(MachineTagConstant.USER_TYPE_MAINTAIN);
            machineTag.setTagId(Long.valueOf(tagId));
            machineTagList.add(machineTag);
        }
        return machineTagList;
    }

    /**
     * @description: 找到车辆未绑定的标签进行绑定
     * @author: mo.shanyong
     * @date: 2024/12/16 9:25
     * @param: machine 车辆
     * @param: machineTagIdList 车辆已绑定的标签
     * @param: toBindTagIds 车辆要绑定的标签id
     */
    private void findNotBindTagToBing(Machine machine,List<Integer> machineTagIdList,List<Integer> toBindTagIds,AccountUser accountUser){
        //如果该车辆的标签等于要绑定的标签Id,则不需要再进行绑定
        if (new HashSet<>(machineTagIdList).containsAll(toBindTagIds) && machineTagIdList.size() == toBindTagIds.size()){
            return;
        }
        //找到现在没绑定的标签Id
        List<Integer> finalMachineTagIdList = machineTagIdList;
        List<Integer> noBindTagIdList = toBindTagIds.stream().filter(id ->{
            return !finalMachineTagIdList.contains(id);
        }).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(noBindTagIdList)){
            return;
        }
        List<MachineTag> addMachineTags = this.getMachineTagByMId(noBindTagIdList, accountUser, machine);
        //绑定
        machineTagDao.insertBatch(addMachineTags);
    }

    /**
     * @description: 找到已经绑定的标签去取消绑定，禁用的标签除外
     * @author: mo.shanyong
     * @date: 2024/12/16 9:32
     * @param: machine 车辆
     * @param: machineTagList 车辆已绑定的标签
     * @param: toBindTagIds 车辆要绑定的标签id
     * @param: accountUser
     */
    private void findBindToNotBind(Machine machine,List<Integer> machineTagIdList,List<Integer> toBindTagIds,List<Integer> bindDisableTagIds
            ,AccountUser accountUser){
        //找到已经绑定但不是禁用的标签id去取消绑定
        List<Integer> toNotBindTagIds = machineTagIdList.stream().filter(id -> {
            return !toBindTagIds.contains(id) && !bindDisableTagIds.contains(id);
        }).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(toNotBindTagIds)){
            return;
        }
        machineTagDao.cancelTagByMachineIds(Arrays.asList(machine.getMachineId()),toNotBindTagIds,MachineTagConstant.CANCEL_TYPE_HAND, accountUser.getAccountUserId(),
                accountUser.getPhone(), MachineTagConstant.USER_TYPE_MAINTAIN);
    }
}
